//
//  HomeContainer.swift
//  home
//
//  Created by Yun Zeng on 2018/11/25.
//  Copyright © 2018 Yun Zeng. All rights reserved.
//

import Foundation

// 家庭容器管理
// 容器管理所属的所有设备
class HomeContainerManager: Codable {
    // 所属家庭
    var home: Home?
    
    var containers: [HMContainer] {
        didSet {
            // 关系链初始化 Container->Accessory->Service->Characteristic
            for container in self.containers {
                for accessory in container.accessories {
                    accessory.container = container
                    for service in accessory.services {
                        service.accessory = accessory
                        for characteristic in service.characteristics {
                            characteristic.service = service
                        }
                    }
                }
            }
        }
    }
    init(containers: [HMContainer]) {
        self.containers = containers
        // 关系链初始化 Container->Accessory->Service->Characteristic
        for container in self.containers {
            for accessory in container.accessories {
                accessory.container = container
                for service in accessory.services {
                    service.accessory = accessory
                    for characteristic in service.characteristics {
                        characteristic.service = service
                    }
                }
            }
        }
    }
    
    // JSON 数据编解码
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.containers)
    }
    
    public required convenience init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let containers = try container.decode([HMContainer].self)
        self.init(containers: containers)
    }
    
    // 服务查找
    func findService(aid: String, sid: Int) -> HMService? {
        for container in self.containers {
            for accessory in container.accessories {
                if accessory.id == aid {
                    for service in accessory.services {
                        if service.id == sid {
                            return service
                        }
                    }
                }
            }
        }
        return nil
    }
    
    // 表层用户层服务于设备层服务进行关联
    func linkService(surface: Service) -> HMService? {
        if let service = self.findService(aid: surface.aid, sid: surface.sid) {
            service.surface = surface
            return service
        }
        return nil
    }
    
    // 发现未被呈现的设备服务
    func findServiceUnconnected() -> [HMService]? {
        var services = [HMService]()
        for container in self.containers {
            for accessory in container.accessories {
                for service in accessory.services {
                    if service.surface == nil {
                        services.append(service)
                    }
                }
            }
        }
        if services.count == 0 {
            return nil
        }
        return services
    }
    
    // 需要和服务器同步数据
    func sync() {
        let msg = CloudMessage(path: HomeMessagePath.container.rawValue, method: .get, data: nil)
        msg.home = self.home?.id
        CloudClient.instance.sendMessage(msg: msg)
    }
}
// 调试打印信息
extension HomeContainerManager: CustomStringConvertible {
    var description: String {
        let data = try! JSONEncoder().encode(self.containers)
        return String(data: data, encoding: .utf8)!
    }
}

// 容器消息处理
extension HomeContainerManager: CloudMessageHandler {
    // 容器属性描述描述
    struct Container: Codable {
        var id: String
        var reachable: Bool
        var version: Int?
        var characteristics: [Characteristic]?
        
        
        private enum CodingKeys: String, CodingKey {
            case id = "container"
            case reachable
            case version
            case characteristics
        }
        
        // 属性值
        struct Characteristic: Codable {
            var aid: String
            var sid: Int
            var cid: Int
            var value: AnyJSONType
        }
    }
    
    // 查找容器
    func findContainer(id: String) -> HMContainer? {
        for c in self.containers {
            if c.id == id {
                return c
            }
        }
        return nil
    }
    
    func findAccessory(id: String) -> HMAccessory? {
        for c in self.containers {
            for a in c.accessories {
                if a.id == id {
                    return a
                }
            }
        }
        return nil
    }
    
    // 更新属性
    func updateCharacteristic(char: Container.Characteristic) -> Bool {
        if let characteristic = self.findAccessory(id: char.aid)?.findService(sid: char.sid)?.findCharacteristic(id: char.cid) {
            characteristic.value = char.value
            return true
        }
        return false
    }
    
    // 属性状态更新
    func handleCharacteristic(msg: CloudMessage) -> CloudMessageError {
        guard let data = msg.data else {
            return .invalidParameter
        }
        
        if msg.method == .put {
            if let chars = try? JSONDecoder().decode([Container.Characteristic].self, from: data) {
                for char in chars {
                    _ = self.updateCharacteristic(char: char)
                }
            }
        }
        return .success
    }
    
    // 处理属性值
    func handleContainerCharacteristic(msg: CloudMessage) -> CloudMessageError {
        guard let data = msg.data else {
            return .invalidParameter
        }
        
        // 所有所有最新的状态数据
        if msg.method == .get {
            if let cs = try? JSONDecoder().decode([Container].self, from: data) {
                // 检查是否需要更新容器数据
                for c in cs {
                    if let container = self.findContainer(id: c.id) {
                        if container.version != c.version {
                            self.sync()
                            break
                        }
                    } else {
                        self.sync()
                        break
                    }
                }
                // 更新容器
                for c in cs {
                    if let chars = c.characteristics {
                        for char in chars {
                            _ = self.updateCharacteristic(char: char)
                        }
                    }
                }
            }
            return .success
        }
            
        // 推送状态更新
        else if msg.method == .put {
            if let container = try? JSONDecoder().decode(Container.self, from: data) {
                
                if let c = self.findContainer(id: container.id), let version = container.version  {
                    if version != c.version {
                        self.sync()
                        return .success
                    }
                }
                
                if let chars = container.characteristics {
                    for char in chars {
                        _ = self.updateCharacteristic(char: char)
                    }
                }
            }
        }
        return .success
    }
    
    // 处理容器获取结果
    func handleContainer(msg: CloudMessage) -> CloudMessageError {
        guard let data = msg.data else {
            return .invalidParameter
        }
        
        if msg.method == .get {
            guard let containers = try? JSONDecoder().decode([HMContainer].self, from: data) else {
                return .invalidParameter
            }
            self.containers = containers
            self.home?.needUpdate(isContainer: true)
        }
        return .success
    }
    
    
    func handle(msg: CloudMessage) -> CloudMessageError {
        guard let path = HomeMessagePath(rawValue: msg.path) else {
            return .invalidParameter
        }
        
        switch path {
        case .containerCharacteristic:
            return self.handleContainerCharacteristic(msg: msg)
            
        case .container:
            return self.handleContainer(msg: msg)
            
        case .characteristic:
            return self.handleCharacteristic(msg: msg)
            
        default:
            return .success
        }
    }
    
    
    func clientStateChange(state: CloudClient.State) {
        // 当网络断开连接时，显示所有的服务状态为正在更新
        if state == .disconnect {
            for container in self.containers {
                for accessory in container.accessories {
                    for service in accessory.services {
                        service.needUpdate(state: .update)
                    }
                }
            }
        }
    }
}




